package com.bolt.report.engine.fill;

import com.bolt.common.collection.IteratorUtil;
import com.bolt.common.utils.ArrayUtil;
import com.bolt.convention.data.Record;
import com.bolt.report.definition.DataSetDefinition;
import com.bolt.report.engine.*;
import com.bolt.report.engine.query.QueryExecute;
import com.bolt.report.engine.query.QueryExecuteFactory;
import com.bolt.report.exception.ReportException;

import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class FillDataSet implements BRDataSet, Serializable {

    protected Map<String, FillField> fieldsMap;

    protected FillField[] fields;


    protected BRSortField[] sortFields;

    protected BRDataSource dataSource;

    protected Map<String, Object> parameters;

    protected DataSetDefinition dataSetDefinition;


    public FillDataSet(List<FillField> fields, List<BRSortField> sortFields, DataSetDefinition dataSetDefinition,Map<String, Object> parameters) {
        this.dataSetDefinition = dataSetDefinition;
        if (IteratorUtil.isEmpty(fields)) {
            throw new ReportException("report is empty");
        }
        this.setFields(ArrayUtil.toArray(fields, FillField.class));
        if (IteratorUtil.isEmpty(sortFields)) {
            this.sortFields = new BRSortField[0];
        } else {
            this.sortFields = ArrayUtil.toArray(sortFields, BRSortField.class);
        }
        this.parameters = parameters;
        initDatasource();
    }



    private void setFields(FillField[] brFields) {
        if (brFields != null && brFields.length > 0) {
            fieldsMap = new HashMap<>();
            fields = brFields;
            for (int i = 0; i < brFields.length; i++) {
                fieldsMap.put(brFields[i].getName(), fields[i]);
            }
        }
    }

    protected void setValues() throws ReportException {
        for (FillField field : fields) {
            field.setValue(dataSource.getFieldValue(field));
        }
    }

    @Deprecated
    public boolean next() throws ReportException {
        boolean hasNext = false;
        if (dataSource != null) {
            hasNext = dataSource.next();
            setValues();
        }
        return hasNext;
    }


    public void initDatasource() throws ReportException {
        if (dataSource == null) {
            dataSource = (BRDataSource) getParameterValue(ReportConstants.REPORT_DATA_SOURCE);
            if (dataSource == null) {
                QueryExecuteFactory queryExecuteFactory = ObjectFactory.getQueryExecuterFactory();
                QueryExecute queryExecuter = queryExecuteFactory.createQueryExecuter(dataSetDefinition, parameters);
                dataSource = queryExecuter.createBRDataSource();
            }
        }
        if (ArrayUtil.isNotEmpty(this.sortFields)) {
            dataSource.sort(this.sortFields);
        }
    }

    public FillReturnValue initBindData() {
        FillReturnValue returnValues = new FillReturnValue();
        while (dataSource != null && dataSource.next()) {
            Record data = new Record();
            for (FillField field : fields) {
                data.put(field.getName(), dataSource.getFieldValue(field));
            }
            returnValues.put(data);
        }

        returnValues.setList(dataSetDefinition.isList());
        returnValues.setPage(dataSetDefinition.isPage());
        returnValues.reStart();
        return returnValues;
    }

    public Object getParameterValue(String parameterName) {
        return this.parameters.get(parameterName);
    }

    @Override
    public BRField[] getFields() {
        return this.fields;
    }

    public BRField getField(String fieldName) {
        return fieldsMap.get(fieldName);
    }

    @Override
    public BRSortField[] getSortFields() {
        return this.sortFields;
    }


    public Map<String, Object> getParameters() {
        return parameters;
    }

    public void setParameters(Map<String, Object> parameters) {
        this.parameters = parameters;
    }
}